﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Resources;
using Gmantis.Controls.Resources;

namespace Gmantis.Controls
{
    public enum MessageBoxButton
    {
        OK,
        OKCancel,
        YesNoCancel,
        YesNo
    }

    public enum MessageBoxIcon
    {
        None,
        Error,
        Warning,
        Information,
        Question
    }

    [TemplateVisualState(Name = "Question", GroupName = "IconStates"), 
    TemplateVisualState(Name = "Warning", GroupName = "IconStates"), 
    TemplateVisualState(Name = "Error", GroupName = "IconStates"), 
    TemplatePart(Name = "Buttons", Type = typeof(Panel)), 
    StyleTypedProperty(Property = "ButtonStyle", StyleTargetType = typeof(Button)), 
    TemplateVisualState(Name = "Information", GroupName = "IconStates"), 
    TemplateVisualState(Name = "Normal", GroupName = "IconStates"), 
    TemplateVisualState(Name = "MouseOver", GroupName = "CommonStates"), 
    TemplateVisualState(Name = "Disabled", GroupName = "CommonStates"), 
    TemplatePart(Name = "Icon", Type = typeof(Image))]
    public class MessageBoxContent : Control
    {
        // Fields
        internal Panel _elementButtons;
        internal Image _elementIcon;
        private bool _throwIsMouseOverChanged;
        public static readonly DependencyProperty ButtonProperty = DependencyProperty.Register("Button", typeof(MessageBoxButton), typeof(MessageBoxContent), new PropertyMetadata(new PropertyChangedCallback(MessageBoxContent.OnButtonPropertyChanged)));
        internal const string ButtonsElementName = "Buttons";
        public static readonly DependencyProperty ButtonStyleProperty = DependencyProperty.Register("ButtonStyle", typeof(Style), typeof(MessageBoxContent), null);
        public static readonly DependencyProperty CancelTextProperty = DependencyProperty.Register("CancelText", typeof(string), typeof(MessageBoxContent), null);
        internal static readonly DependencyProperty ForceMouseOverProperty = DependencyProperty.Register("ForceMouseOver", typeof(bool), typeof(MessageBoxContent), new PropertyMetadata(new PropertyChangedCallback(MessageBoxContent.OnForceMouseOverPropertyChanged)));
        internal const string IconElementName = "Icon";
        public static readonly DependencyProperty IconProperty = DependencyProperty.Register("Icon", typeof(MessageBoxIcon), typeof(MessageBoxContent), new PropertyMetadata(new PropertyChangedCallback(MessageBoxContent.OnIconPropertyChanged)));
        public static readonly DependencyProperty IsMouseOverProperty = DependencyProperty.Register("IsMouseOver", typeof(bool), typeof(MessageBoxContent), new PropertyMetadata(new PropertyChangedCallback(MessageBoxContent.OnIsMouseOverPropertyChanged)));
        public static readonly DependencyProperty MessageProperty = DependencyProperty.Register("Message", typeof(string), typeof(MessageBoxContent), null);
        public static readonly DependencyProperty NoTextProperty = DependencyProperty.Register("NoText", typeof(string), typeof(MessageBoxContent), null);
        public static readonly DependencyProperty OKTextProperty = DependencyProperty.Register("OKText", typeof(string), typeof(MessageBoxContent), null);
        public static readonly DependencyProperty YesTextProperty = DependencyProperty.Register("YesText", typeof(string), typeof(MessageBoxContent), null);

        // Events
        public event Action<MessageBoxResult> ButtonClick;
        public event EventHandler<PropertyChangedEventArgs<bool>> IsMouseOverChanged;

        // Methods
        public MessageBoxContent()
        {
            RoutedEventHandler handler = null;
            DependencyPropertyChangedEventHandler handler2 = null;
            this._throwIsMouseOverChanged = true;
            base.DefaultStyleKey = typeof(MessageBoxContent);
            if (handler == null)
            {
                handler = delegate(object param0, RoutedEventArgs param1)
                {
                    this.ChangeVisualStateIcon(false);
                    this.ChangeVisualStateCommon(false);
                };
            }
            base.Loaded += handler;
            if (handler2 == null)
            {
                handler2 = (s, a) => this.ChangeVisualStateCommon(true);
            }
            base.IsEnabledChanged += handler2;
            base.MouseEnter += new MouseEventHandler(this.Control_MouseEnter);
            base.MouseLeave += new MouseEventHandler(this.Control_MouseLeave);
            this.SetCustomDefaultValues();
        }

        private void AddButton(string text, MessageBoxResult result)
        {
            Button button = new Button
            {
                Content = text
            };
            this._elementButtons.Children.Add(button);
            if (this.ButtonStyle != null)
            {
                button.Style = this.ButtonStyle;
            }
            button.Click += delegate(object s, RoutedEventArgs e)
            {
                if (this.ButtonClick != null)
                {
                    this.ButtonClick(result);
                }
            };
        }

        private void Control_MouseEnter(object sender, MouseEventArgs e)
        {
            if (InputEventArgs.GetPointerType(e) == PointerDeviceType.Mouse)
            {
                this.IsMouseOver = true;
            }
        }

        private void Control_MouseLeave(object sender, MouseEventArgs e)
        {
            if (InputEventArgs.GetPointerType(e) == PointerDeviceType.Mouse)
            {
                this.IsMouseOver = false;
            }
        }

        protected void ChangeVisualStateCommon(bool useTransitions)
        {
            if (!base.IsEnabled)
            {
                VisualStateHelper.GoToState(this, "Disabled", useTransitions);
            }
            if (base.IsEnabled)
            {
                VisualStateHelper.GoToState(this, "MouseOver", useTransitions);
            }
        }

        protected void ChangeVisualStateIcon(bool useTransitions)
        {
            if (this.Icon == MessageBoxIcon.Information)
            {
                VisualStateHelper.GoToState(this, "Information", useTransitions);
            }
            if (this.Icon == MessageBoxIcon.None)
            {
                VisualStateHelper.GoToState(this, "Normal", useTransitions);
            }
            if (this.Icon == MessageBoxIcon.Question)
            {
                VisualStateHelper.GoToState(this, "Question", useTransitions);
            }
            if (this.Icon == MessageBoxIcon.Warning)
            {
                VisualStateHelper.GoToState(this, "Warning", useTransitions);
            }
            if (this.Icon == MessageBoxIcon.Error)
            {
                VisualStateHelper.GoToState(this, "Error", useTransitions);
            }
        }

        private T GetTemplateChild<T>(string childName, bool required, ref string errors) where T : class
        {
            DependencyObject templateChild = base.GetTemplateChild(childName);
            ApplyTemplateHelper.VerifyTemplateChild(typeof(T), "template part", childName, templateChild, required, ref errors);
            return (templateChild as T);
        }

        private static Storyboard GetTemplateChildResource(FrameworkElement root, string resourceName, bool required, ref string errors)
        {
            return GetTemplateChildResource<Storyboard>(root, resourceName, required, ref errors);
        }

        private static T GetTemplateChildResource<T>(FrameworkElement root, string resourceName, bool required, ref string errors) where T : class
        {
            object child = root.Resources[resourceName];
            ApplyTemplateHelper.VerifyTemplateChild(typeof(T), "resource", resourceName, child, required, ref errors);
            return (child as T);
        }

        private void InitializeButtonsPart()
        {
            this.OKText = this.OKText ?? Local_Resources.OK;
            this.CancelText = this.CancelText ?? Local_Resources.Cancel;
            this.YesText = this.YesText ?? Local_Resources.Yes;
            this.NoText = this.NoText ?? Local_Resources.No;
            this.OnButtonChanged(MessageBoxButton.OK);
        }

        private void OnAfterApplyTemplate()
        {
            this.OnIconChanged(MessageBoxIcon.None);
        }

        public override void OnApplyTemplate()
        {
            string errors = string.Empty;
            base.OnApplyTemplate();
            this._elementButtons = this.GetTemplateChild<Panel>("Buttons", true, ref errors);
            if (this._elementButtons != null)
            {
                this.InitializeButtonsPart();
            }
            this._elementIcon = this.GetTemplateChild<Image>("Icon", true, ref errors);
            if (!string.IsNullOrEmpty(errors))
            {
                if ((base.Template != null) && !PlatformIndependent.IsInDesignMode(this))
                {
                    throw new InvalidOperationException(string.Format(System.Globalization.CultureInfo.InvariantCulture, "Template cannot be applied to MessageBoxContent.\nDetails: {0}", new object[] { errors }));
                }
            }
            else
            {
                this.ChangeVisualStateIcon(false);
                this.ChangeVisualStateCommon(false);
                this.OnAfterApplyTemplate();
            }
        }

        private void OnButtonChanged(MessageBoxButton oldValue)
        {
            if (this._elementButtons != null)
            {
                this._elementButtons.Children.Clear();
                switch (this.Button)
                {
                    case MessageBoxButton.OK:
                        this.AddButton(this.OKText, MessageBoxResult.OK);
                        return;

                    case MessageBoxButton.OKCancel:
                        this.AddButton(this.OKText, MessageBoxResult.OK);
                        this.AddButton(this.CancelText, MessageBoxResult.Cancel);
                        return;

                    case MessageBoxButton.YesNoCancel:
                        this.AddButton(this.YesText, MessageBoxResult.Yes);
                        this.AddButton(this.NoText, MessageBoxResult.No);
                        this.AddButton(this.CancelText, MessageBoxResult.Cancel);
                        return;

                    case MessageBoxButton.YesNo:
                        this.AddButton(this.YesText, MessageBoxResult.Yes);
                        this.AddButton(this.NoText, MessageBoxResult.No);
                        return;
                }
            }
        }

        private static void OnButtonPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            MessageBoxContent content = d as MessageBoxContent;
            MessageBoxButton oldValue = (MessageBoxButton)e.OldValue;
            content.OnButtonChanged(oldValue);
        }

        private static void OnForceMouseOverPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            (d as MessageBoxContent).ChangeVisualStateCommon(true);
        }

        private void OnIconChanged(MessageBoxIcon oldValue)
        {
            if ((this._elementIcon != null) && (this.Icon != MessageBoxIcon.None))
            {
                Uri uriResource = new Uri("/Gmantis.Controls;component/Resources/" + this.Icon + ".png", UriKind.Relative);
                try
                {
                    StreamResourceInfo resourceStream = Application.GetResourceStream(uriResource);
                    if (resourceStream != null)
                    {
                        BitmapImage image = new BitmapImage();
                        image.SetSource(resourceStream.Stream);
                        this._elementIcon.Source = image;
                    }
                }
                catch
                {
                }
            }
        }

        private static void OnIconPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            MessageBoxContent content = d as MessageBoxContent;
            MessageBoxIcon oldValue = (MessageBoxIcon)e.OldValue;
            content.OnIconChanged(oldValue);
            content.ChangeVisualStateIcon(true);
        }

        private static void OnIsMouseOverPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            MessageBoxContent sender = d as MessageBoxContent;
            if ((sender.IsMouseOverChanged != null) && sender._throwIsMouseOverChanged)
            {
                PropertyChangedEventArgs<bool> args = new PropertyChangedEventArgs<bool>
                {
                    OldValue = (bool)e.OldValue,
                    NewValue = (bool)e.NewValue
                };
                sender.IsMouseOverChanged(sender, args);
            }
            sender.ChangeVisualStateCommon(true);
        }

        private void SetCustomDefaultValues()
        {
        }

        // Properties
        public MessageBoxButton Button
        {
            get { return (MessageBoxButton)GetValue(ButtonProperty); }
            set { SetValue(ButtonProperty, value); }
        }

        public Style ButtonStyle
        {
            get { return (Style)GetValue(ButtonStyleProperty); }
            set { SetValue(ButtonStyleProperty, value); }
        }

        public string CancelText
        {
            get { return (string)GetValue(CancelTextProperty); }
            set { SetValue(CancelTextProperty, value); }
        }

        internal bool ForceMouseOver
        {
            get { return (bool)GetValue(ForceMouseOverProperty); }
            set { SetValue(ForceMouseOverProperty, value); }
        }

        public MessageBoxIcon Icon
        {
            get { return (MessageBoxIcon)GetValue(IconProperty); }
            set { SetValue(IconProperty, value); }
        }

        public bool IsMouseOver
        {
            get { return (bool)GetValue(IsMouseOverProperty); }
            internal set { SetValue(IsMouseOverProperty, value); }
        }

        public string Message
        {
            get { return (string)GetValue(MessageProperty); }
            set { SetValue(MessageProperty, value); }
        }

        public string NoText
        {
            get { return (string)GetValue(NoTextProperty); }
            set { SetValue(NoTextProperty, value); }
        }

        public string OKText
        {
            get { return (string)GetValue(OKTextProperty); }
            set { SetValue(OKTextProperty, value); }
        }

        public string YesText
        {
            get { return (string)GetValue(YesTextProperty); }
            set { SetValue(YesTextProperty, value); }
        }
    }
}
